﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using Newtonsoft.Json;
using System.IO.Pipes;
using Main.Packets;
using System.Threading;

namespace Main.PrimitivesCommunication
{
    public class Primitive
    {
        #region Attributs

        private Primitives primitive;

        private byte adresseSource;
        private byte adresseDestination;
        private byte adresseReponse;

        private string donneesUtilisateur;

        private Raisons raison;

        #endregion

        #region Constructeurs

        private Primitive()
        {
        }

        private Primitive(Primitives primitive, byte adresseSource, byte adresseDestination, byte adresseReponse)
        {
            this.primitive = primitive;
            this.adresseSource = adresseSource;
            this.adresseDestination = adresseDestination;
            this.adresseReponse = adresseReponse;
        }

        private Primitive(Primitives primitive, string donneesUtilisateur)
        {
            this.primitive = primitive;
            this.donneesUtilisateur = donneesUtilisateur;
        }

        private Primitive(Primitives primitive, byte adresseReponse)
        {
            this.primitive = primitive;
            this.adresseReponse = adresseReponse;
        }

        private Primitive(Primitives primitive, byte adresseReponse, Raisons raison)
        {
            this.primitive = primitive;
            this.adresseReponse = adresseReponse;
            this.raison = raison;
        }

        #endregion

        #region Propriétés

        public Int16 Size
        {
            get
            {
                Int16 retour;
                switch(primitive)
                {
                    case PrimitivesCommunication.Primitives.NConnectConfirmation:
                    case PrimitivesCommunication.Primitives.NConnectResponse:
                    case PrimitivesCommunication.Primitives.NDisconnectRequest:
                        retour = 1;
                        break;
                    case PrimitivesCommunication.Primitives.NConnectRequest:
                    case PrimitivesCommunication.Primitives.NConnectIndication:
                    case PrimitivesCommunication.Primitives.NDisconnectIndication:
                        retour = 2;
                        break;
                    case PrimitivesCommunication.Primitives.NDataRequest:
                    case PrimitivesCommunication.Primitives.NDataIndication:
                        retour = 16;
                        break;
                    default:
                        throw new NotImplementedException();
                }
                return retour;
            }
        }
        public byte AdresseSource { get { return adresseSource; } set { adresseSource = value; } }
        public byte AdresseDestination { get { return adresseDestination; } set { adresseDestination = value; } }
        public byte AdresseReponse { get { return adresseReponse; } set { adresseReponse = value; } }

        public string DonneesUtilisateur { get { return donneesUtilisateur; } set { donneesUtilisateur = value; } }

        public Raisons Raison { get { return raison; } set { raison = value; } }

        public Primitives Primitives { get { return primitive; } set { primitive = value; } }

        #endregion

        #region Méthodes de création des primitives

        static public Primitive CreateNConnectReq(byte adresseSource, byte adresseDestination)
        {
            return new Primitive(Primitives.NConnectRequest, adresseSource, adresseDestination, 0);
        }
        static public Primitive CreateNConnectInd(byte adresseSource, byte adresseDestination)
        {
            return new Primitive(Primitives.NConnectIndication, adresseSource, adresseDestination, 0);
        }
        static public Primitive CreateNConnectResp(byte adresseReponse)
        {
            return new Primitive(Primitives.NConnectResponse, 0, 0, adresseReponse);
        }
        static public Primitive CreateNConnectConf(byte adresseReponse)
        {
            return new Primitive(Primitives.NConnectConfirmation, 0, 0, adresseReponse);
        }

        static public Primitive CreateNDataReq(string donneesUtilisateur)
        {
            return new Primitive(Primitives.NDataRequest, donneesUtilisateur);
        }
        static public Primitive CreateNDataInd(string donneesUtilisateur)
        {
            return new Primitive(Primitives.NDataIndication, donneesUtilisateur);
        }

        static public Primitive CreateNDisconnectReq(byte adresseReponse)
        {
            return new Primitive(Primitives.NDisconnectRequest, adresseReponse);
        }
        static public Primitive CreateNDisconnectInd(byte adresseReponse, Raisons raison)
        {
            return new Primitive(Primitives.NDisconnectIndication, adresseReponse, raison);
        }

        #endregion

        #region Serializer

        public void WriteJson(StreamWriter sw)
        {
            sw.WriteLine(JsonConvert.SerializeObject(this));
            Console.WriteLine("111->" + JsonConvert.SerializeObject(this) + "\n");
        }

        public static Primitive ReadJson(StreamReader sr)
        {
            Primitive p = null;

            //if (sr.BaseStream.Length > 0)
            //{
            Thread.Sleep(500);
                string str = sr.ReadLine();
                p = JsonConvert.DeserializeObject<Primitive>(str) as Primitive;
            //}
            return p;
        }

        public static Primitive ReadJson(string str)
        {
            return JsonConvert.DeserializeObject<Primitive>(str) as Primitive;
        }

        #endregion

        public override string ToString()
        {
            string toString =  Enum.GetName(typeof(Primitives), primitive);

            if (this.primitive == Primitives.NConnectRequest || this.primitive == Primitives.NConnectIndication)
                toString += ("Source : " + this.adresseSource + " Destination : " + this.adresseDestination);
            else if (this.primitive == Primitives.NConnectResponse || this.primitive == Primitives.NConnectConfirmation || this.primitive == Primitives.NDisconnectRequest)
                toString += ("adresse reponse : " + this.adresseReponse);
            else if (this.primitive == Primitives.NDisconnectIndication)
                toString += ("adresse reponse : " + this.adresseReponse + " Raison : " + this.raison);
            else if (this.primitive == Primitives.NConnectResponse || this.primitive == Primitives.NConnectConfirmation)
                toString += ("Données utilisateurs : " + this.donneesUtilisateur);
            
            return toString;
        }
    }
}
